#!/usr/bin/env python
# encoding: utf-8
"""
@author:zwb
@file: views.py
@contact: zwb15083976291@163.com
@time: 2021/10/10
"""
from rest_framework import serializers
from rest_framework.generics import GenericAPIView

from utils.views.funcs import generate_deserial_constrains, query_dict_to_dict, get_dict_error_info
from utils.views.paginate import CommonPaginator, GenericAPIPaginateMixin


class BaseGenericAPIView(GenericAPIView):
    """自定义GenericAPIView"""
    pagination_class = CommonPaginator
    # 通用反序列化校验条件,示例：dict(required=[a,b],optional=[c],default=dict(a=1))
    generic_request_params = None
    # 不同请求方法使用的饭序列化校验条件,示例：dict(get=dict(required=[a,b],optional=[c],defualt_value=dict(a=1)))
    diff_methods_request_params = {}
    serializer_class = None  # 通用序列化器类
    # 不同请求方法使用的序列化器类,示例：dict(get=AAserializer,post=bbserializer)
    diff_methods_serializer_class = {}

    def get_serializer_class(self):
        """获取配置的序列化器类"""
        request = self.request
        serializer_class = None
        if request.method in self.diff_methods_serializer_class or request.method.lower() in self.diff_methods_serializer_class:
            serializer_class = self.diff_methods_serializer_class.get(
                request.method) or self.diff_methods_serializer_class.get(request.method.lower())
        if not serializer_class:
            serializer_class = self.serializer_class
        assert serializer_class, 'serializer_class--diff_methods_serializer_class--属性必须配置一个'

        return serializer_class

    def get_serializer(self, *args, **kwargs):
        """获取序列化器对象"""
        serializer_class = self.get_serializer_class()
        default_context = self.get_serializer_context()
        if kwargs.get('context'):
            kwargs['context'].update(default_context)
        return serializer_class(*args, **kwargs)

    def get_constrains_query_data(self) -> ('constrains', 'query_data'):
        """获取序列化器约束条件"""
        request = self.request
        if request.method in self.diff_methods_request_params or request.method.lower() in self.diff_methods_request_params:
            constrains_dict = self.diff_methods_request_params.get(
                request.method) or self.diff_methods_request_params.get(request.method.lower())
        elif self.generic_request_params:
            constrains_dict = self.generic_request_params
        constrains = generate_deserial_constrains(**constrains_dict)
        if request.method == "GET":
            self._query_data = query_dict_to_dict(request.query_params, constrains=constrains)
        else:
            self._query_data = query_dict_to_dict(request.data, constrains=constrains)
        return constrains, self._query_data

    @property
    def query_data(self):
        if not hasattr(self, '_query_data'):
            raise NotImplementedError('get_constrains_query_data方法必须先调用')
        return getattr(self, '_query_data')

    @property
    def serializer(self):
        if not hasattr(self, '_serializer'):
            raise NotImplementedError('validate_request_params方法必须先调用')
        return getattr(self, '_serializer')

    def validate_request_params(self, *args, **kwargs) -> (bool, 'OK or error_message'):
        """序列化器校验并返回校验结果"""
        constrains, query_data = self.get_constrains_query_data()
        self._serializer = self.get_serializer(*args, data=query_data,
                                               deserial_fields=constrains, **kwargs)
        try:
            self._serializer.is_valid(raise_exception=True)
        except serializers.ValidationError as e:
            message = get_dict_error_info(self._serializer.errors)
            return False, message
        else:
            return True, 'OK'


class BasePaginateGenericAPIView(GenericAPIPaginateMixin, BaseGenericAPIView):
    """通用分页拓展视图"""
    pass
